Strukturierte Outputs mit OpenAI und Pydantic
Marcin Tabisz
Large Language Models (LLMs) sind bemerkenswert gut darin, Dokumente zu lesen und zu verstehen. Fotografieren Sie einen Beleg oder scannen Sie eine Rechnung, und das Modell wird Ihnen alles darauf nennen - den Namen des Händlers, die einzelnen Posten, die Gesamtsumme, die Steuer. Das Problem ist jedoch, dass es Ihnen diese Informationen in Prosa mitteilt. Und Prosa, so präzise sie auch sein mag, lässt sich nicht ohne Weiteres in eine Datenbank laden, mit einem Ground-Truth-Label vergleichen oder zur Berechnung eines F1-Scores heranziehen. Genau vor dieser Herausforderung standen wir im Forschungsprojekt FewTuRe , das sich mit Few-Shot Fine-tuning für die Informationsextraktion aus Quittungen und Rechnungen befasste. Wir benötigten das Modell, um strukturierte Informationen aus Dokumenten zu extrahieren, aber wir mussten auch sicherstellen, dass diese Informationen zuverlässig in einem maschinenlesbaren Format ankommen, das exakt unserem Ground-Truth-Datenschema entspricht. Eine Antwort, die die Gesamtsumme einmal unter „total_amount“ und beim nächsten Mal unter „total“ aufführte, war für unsere Evaluation-Pipeline ebenso nutzlos wie eine falsche Antwort. Konsistenz war kein „Nice-to-have“, sondern eine strikte Anforderung. Diese Erfahrung hat uns eines verdeutlicht: Die richtige Antwort zu erhalten, ist nur die halbe Miete. Sie in der richtigen Form zu erhalten, ist die andere Hälfte. In diesem Beitrag geht es um die Lösung dieser zweiten Hälfte. Wir zeigen auf, wie das Feature für Structured Outputs von OpenAI in Kombination mit Pydantic und dem OpenAI Python SDK einen zuverlässigen und eleganten Weg bietet, genau das Ausgabeformat zu erzwingen, das Ihre Anwendung benötigt. Um zu verstehen, warum Structured Outputs wichtig sind, hilft ein Blick darauf, was LLMs standardmäßig produzieren: einen Stream von Tokens, die natürlichen Sprachtext bilden. Selbst wenn Sie ein Modell anweisen, „ein JSON-Objekt zurückzugeben“, bitten Sie es im Grunde nur freundlich darum. Es gibt keine Garantie. In der Praxis führt dies zu Antworten wie: Valides JSON – großartig, aber verlassen Sie sich nicht jedes Mal darauf. JSON, das in einen Markdown-Codeblock eingebettet ist, den Sie zuerst entfernen müssen. JSON mit halluzinierten oder inkonsistent benannten Schlüsseln. Ein hilfreicher Satz vor dem JSON, der Ihren Parser zum Absturz bringt. Subtil falsche Typen, wie z. B. eine Zahl, die als String zurückgegeben wird, oder eine Liste als kommagetrennter Wert. Für einen Prototyp oder eine Demo ist dies handhabbar. Man schreibt ein wenig Post-Processing-Logik, fängt die Edge-Cases ab und macht weiter. Aber für eine Production-Pipeline, insbesondere wenn der Output direkt in einen Training-Loop oder ein Evaluation-Framework fließt, ist diese Art von Fragilität ein ernsthaftes Problem. In unserem Projekt zur Informationsextraktion verfügten unsere Ground-Truth-Daten über ein wohldefiniertes Schema. Jeder Beleg und jede Rechnung war mit demselben Satz von Feldern, denselben Typen und derselben Struktur gelabelt. Damit die Ausgabe des Modells mit dieser Ground Truth vergleichbar war, musste sie exakt diesem Schema entsprechen. Wir konnten uns keinen Parser leisten, der in 95 % der Fälle funktioniert. Wir brauchten etwas, auf das wir uns wirklich verlassen konnten. Hier kommen strukturierte Outputs ins Spiel.